package nsalt.arch 

import chisel3._
import chisel3.util._

import nsalt._


object RV32I_ALUInstr extends InstrType with Config {
  def ADDI    = BitPat("b????????????_?????_000_?????_0010011")
  def SLLI    = if (DATA_BITS == 32) 
                BitPat("b0000000?????_?????_001_?????_0010011")
           else BitPat("b000000??????_?????_001_?????_0010011")
  def SLTI    = BitPat("b????????????_?????_010_?????_0010011")
  def SLTIU   = BitPat("b????????????_?????_011_?????_0010011")
  def XORI    = BitPat("b????????????_?????_100_?????_0010011")
  def SRLI    = if (DATA_BITS == 32) BitPat("b0000000?????_?????_101_?????_0010011")
                                else BitPat("b000000??????_?????_101_?????_0010011")
  def ORI     = BitPat("b????????????_?????_110_?????_0010011")
  def ANDI    = BitPat("b????????????_?????_111_?????_0010011")
  def SRAI    = if (DATA_BITS == 32) BitPat("b0100000?????_?????_101_?????_0010011")
                                else BitPat("b010000??????_?????_101_?????_0010011")

  def ADD     = BitPat("b0000000_?????_?????_000_?????_0110011")
  def SLL     = BitPat("b0000000_?????_?????_001_?????_0110011")
  def SLT     = BitPat("b0000000_?????_?????_010_?????_0110011")
  def SLTU    = BitPat("b0000000_?????_?????_011_?????_0110011")
  def XOR     = BitPat("b0000000_?????_?????_100_?????_0110011")
  def SRL     = BitPat("b0000000_?????_?????_101_?????_0110011")
  def OR      = BitPat("b0000000_?????_?????_110_?????_0110011")
  def AND     = BitPat("b0000000_?????_?????_111_?????_0110011")
  def SUB     = BitPat("b0100000_?????_?????_000_?????_0110011")
  def SRA     = BitPat("b0100000_?????_?????_101_?????_0110011")

  def AUIPC   = BitPat("b????????????????????_?????_0010111")
  def LUI     = BitPat("b????????????????????_?????_0110111")

  val table = Array(
    ADDI           -> List(InstrI, FuncType.alu, ArithLogicOperType.add),
    SLLI           -> List(InstrI, FuncType.alu, ArithLogicOperType.sll),
    SLTI           -> List(InstrI, FuncType.alu, ArithLogicOperType.slt),
    SLTIU          -> List(InstrI, FuncType.alu, ArithLogicOperType.sltu),
    XORI           -> List(InstrI, FuncType.alu, ArithLogicOperType.xor),
    SRLI           -> List(InstrI, FuncType.alu, ArithLogicOperType.srl),
    ORI            -> List(InstrI, FuncType.alu, ArithLogicOperType.or ),
    ANDI           -> List(InstrI, FuncType.alu, ArithLogicOperType.and),
    SRAI           -> List(InstrI, FuncType.alu, ArithLogicOperType.sra),

    ADD            -> List(InstrR, FuncType.alu, ArithLogicOperType.add),
    SLL            -> List(InstrR, FuncType.alu, ArithLogicOperType.sll),
    SLT            -> List(InstrR, FuncType.alu, ArithLogicOperType.slt),
    SLTU           -> List(InstrR, FuncType.alu, ArithLogicOperType.sltu),
    XOR            -> List(InstrR, FuncType.alu, ArithLogicOperType.xor),
    SRL            -> List(InstrR, FuncType.alu, ArithLogicOperType.srl),
    OR             -> List(InstrR, FuncType.alu, ArithLogicOperType.or ),
    AND            -> List(InstrR, FuncType.alu, ArithLogicOperType.and),
    SUB            -> List(InstrR, FuncType.alu, ArithLogicOperType.sub),
    SRA            -> List(InstrR, FuncType.alu, ArithLogicOperType.sra),

    AUIPC          -> List(InstrU, FuncType.alu, ArithLogicOperType.add),
    LUI            -> List(InstrU, FuncType.alu, ArithLogicOperType.add)
  )
}

object RV32I_BRUInstr extends InstrType {

  def JAL     = BitPat("b????????????????????_?????_1101111")
  def JALR    = BitPat("b????????????_?????_000_?????_1100111")

  def BNE     = BitPat("b???????_?????_?????_001_?????_1100011")
  def BEQ     = BitPat("b???????_?????_?????_000_?????_1100011")
  def BLT     = BitPat("b???????_?????_?????_100_?????_1100011")
  def BGE     = BitPat("b???????_?????_?????_101_?????_1100011")
  def BLTU    = BitPat("b???????_?????_?????_110_?????_1100011")
  def BGEU    = BitPat("b???????_?????_?????_111_?????_1100011")

  val table = Array(

    JAL            -> List(InstrJ, FuncType.bru, ArithLogicOperType.jal),
    JALR           -> List(InstrI, FuncType.bru, ArithLogicOperType.jalr),

    BEQ            -> List(InstrB, FuncType.bru, ArithLogicOperType.beq),
    BNE            -> List(InstrB, FuncType.bru, ArithLogicOperType.bne),
    BLT            -> List(InstrB, FuncType.bru, ArithLogicOperType.blt),
    BGE            -> List(InstrB, FuncType.bru, ArithLogicOperType.bge),
    BLTU           -> List(InstrB, FuncType.bru, ArithLogicOperType.bltu),
    BGEU           -> List(InstrB, FuncType.bru, ArithLogicOperType.bgeu)
  )

  val branchTypeList = List(
    ArithLogicOperType.beq  -> BranchType.B,
    ArithLogicOperType.bne  -> BranchType.B,
    ArithLogicOperType.blt  -> BranchType.B,
    ArithLogicOperType.bge  -> BranchType.B,
    ArithLogicOperType.bltu -> BranchType.B,
    ArithLogicOperType.bgeu -> BranchType.B,
    ArithLogicOperType.call -> BranchType.J,
    ArithLogicOperType.ret  -> BranchType.R,
    ArithLogicOperType.jal  -> BranchType.J,
    ArithLogicOperType.jalr -> BranchType.I
  )
}

object RV32I_LSUInstr extends InstrType {
  def LB      = BitPat("b????????????_?????_000_?????_0000011")
  def LH      = BitPat("b????????????_?????_001_?????_0000011")
  def LW      = BitPat("b????????????_?????_010_?????_0000011")
  def LBU     = BitPat("b????????????_?????_100_?????_0000011")
  def LHU     = BitPat("b????????????_?????_101_?????_0000011")
  def SB      = BitPat("b???????_?????_?????_000_?????_0100011")
  def SH      = BitPat("b???????_?????_?????_001_?????_0100011")
  def SW      = BitPat("b???????_?????_?????_010_?????_0100011")

  val table = Array(
    LB             -> List(InstrI, FuncType.lsu, LoadStoreOperType.lb ),
    LH             -> List(InstrI, FuncType.lsu, LoadStoreOperType.lh ),
    LW             -> List(InstrI, FuncType.lsu, LoadStoreOperType.lw ),
    LBU            -> List(InstrI, FuncType.lsu, LoadStoreOperType.lbu),
    LHU            -> List(InstrI, FuncType.lsu, LoadStoreOperType.lhu),
    SB             -> List(InstrS, FuncType.lsu, LoadStoreOperType.sb ),
    SH             -> List(InstrS, FuncType.lsu, LoadStoreOperType.sh ),
    SW             -> List(InstrS, FuncType.lsu, LoadStoreOperType.sw )
  )
}

object RV64IInstr extends InstrType {
  def ADDIW   = BitPat("b???????_?????_?????_000_?????_0011011")
  def SLLIW   = BitPat("b0000000_?????_?????_001_?????_0011011")
  def SRLIW   = BitPat("b0000000_?????_?????_101_?????_0011011")
  def SRAIW   = BitPat("b0100000_?????_?????_101_?????_0011011")
  def SLLW    = BitPat("b0000000_?????_?????_001_?????_0111011")
  def SRLW    = BitPat("b0000000_?????_?????_101_?????_0111011")
  def SRAW    = BitPat("b0100000_?????_?????_101_?????_0111011")
  def ADDW    = BitPat("b0000000_?????_?????_000_?????_0111011")
  def SUBW    = BitPat("b0100000_?????_?????_000_?????_0111011")

  def LWU     = BitPat("b???????_?????_?????_110_?????_0000011")
  def LD      = BitPat("b???????_?????_?????_011_?????_0000011")
  def SD      = BitPat("b???????_?????_?????_011_?????_0100011")

  val table = Array(
    ADDIW          -> List(InstrI, FuncType.alu, ArithLogicOperType.addw),
    SLLIW          -> List(InstrI, FuncType.alu, ArithLogicOperType.sllw),
    SRLIW          -> List(InstrI, FuncType.alu, ArithLogicOperType.srlw),
    SRAIW          -> List(InstrI, FuncType.alu, ArithLogicOperType.sraw),
    SLLW           -> List(InstrR, FuncType.alu, ArithLogicOperType.sllw),
    SRLW           -> List(InstrR, FuncType.alu, ArithLogicOperType.srlw),
    SRAW           -> List(InstrR, FuncType.alu, ArithLogicOperType.sraw),
    ADDW           -> List(InstrR, FuncType.alu, ArithLogicOperType.addw),
    SUBW           -> List(InstrR, FuncType.alu, ArithLogicOperType.subw),

    LWU            -> List(InstrI, FuncType.lsu, LoadStoreOperType.lwu),
    LD             -> List(InstrI, FuncType.lsu, LoadStoreOperType.ld ),
    SD             -> List(InstrS, FuncType.lsu, LoadStoreOperType.sd)
  )
}

object RVIInstr extends Config {
  val table = RV32I_ALUInstr.table ++ 
              RV32I_BRUInstr.table ++ 
              RV32I_LSUInstr.table ++
  (if (DATA_BITS == 64) RV64IInstr.table else Array())
}
